package com.dkts.oil.test.road;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dkts.oil.converter.GeometryConverter;
import com.dkts.oil.util.GeoOutUtil;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.index.strtree.STRtree;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class PolygonCutter {
    private static final GeometryFactory geometryFactory = new GeometryFactory();
//    private static final PolygonBufferImpl polygonBuffer = new PolygonBufferImpl();

    public static void main(String[] args) {
        // 多边形 JSON
        // 原始4个多边形 JSON
        String polygonJson = "[{\"geometry\":{\"coordinates\":[[[118.0217605842,29.5048647156],[118.0244888616,29.5225551304],[118.0141479805,29.5237217375],[118.0114218194,29.5060311229],[118.0217605842,29.5048647156]]],\"type\":\"Polygon\"},\"label\":\"43\",\"id\":183667},"
                + "{\"geometry\":{\"coordinates\":[[[118.929448383,29.1372875772],[118.9397294803,29.1360384462],[118.9500102766,29.1347883964],[118.9514645514,29.1436293925],[118.9411827116,29.1448795477],[118.9309005708,29.1461287839],[118.929448383,29.1372875772]]],\"type\":\"Polygon\"},\"label\":\"43\",\"id\":194537},"
                + "{\"geometry\":{\"coordinates\":[[[118.9309005708,29.1461287839],[118.9323530595,29.1549698019],[118.922069574,29.1562182243],[118.9206181292,29.1473771011],[118.9309005708,29.1461287839]]],\"type\":\"Polygon\"},\"label\":\"43\",\"id\":101834},"
                + "{\"geometry\":{\"coordinates\":[[[119.0513372419,29.1133972339],[119.0498731444,29.1045569161],[119.0395974532,29.1058159418],[119.0381347005,29.0969753283],[119.0586836961,29.0944565703],[119.0601485325,29.1032969719],[119.061613672,29.1121371838],[119.0513372419,29.1133972339]]],\"type\":\"Polygon\"},\"label\":\"42\",\"id\":215131}]";

        // 切割线 JSON
        String lineJson = "{\"coordinates\":[[119.1069,29.0752],[117.2917,29.8122]],\"type\":\"LineString\"}";

        // 解析多边形
        List<Geometry> polygons = parsePolygons(polygonJson);

        // 解析切割线
        LineString cuttingLine = parseLineString(lineJson);
        routerGeometry(polygons, cuttingLine);
    }

    public static List<Coordinate> routerGeometry(List<Geometry> polygons, LineString cuttingLine) {
        Coordinate coordinate = cuttingLine.getCoordinates()[0];

        // 使用STRtree空间索引提升障碍物查询效率
        STRtree tree = new STRtree();
        for (int i = 0; i < polygons.size(); i++) {
            tree.insert(polygons.get(i).getEnvelopeInternal(), polygons.get(i));
        }

        List<DistanceIndex> distanceIndices = new ArrayList<>();

        // 使用STRtree查询与切割线相交的障碍物
        List<Geometry> possiblePolygons = tree.query(cuttingLine.getEnvelopeInternal());

        for (Geometry polygon : possiblePolygons) {
            Geometry intersection = polygon.intersection(cuttingLine);
            if (intersection.getCoordinates().length == 0) {
                continue;
            }

            Coordinate coordinate01 = intersection.getCoordinates()[0];
            Coordinate coordinate02 = intersection.getCoordinates()[intersection.getCoordinates().length - 1];
            double distance = coordinate.distance(coordinate01);
            distanceIndices.add(new DistanceIndex(polygons.indexOf(polygon), distance, coordinate01, coordinate02));
        }

        // 按照距离排序，优先绕过最近的障碍物
        distanceIndices.sort(Comparator.comparingDouble(DistanceIndex::getDistance));

        List<Coordinate> coordinates = new ArrayList<>();
        coordinates.add(coordinate); // 起点加入路径

        List<LineString> pathSegments = new ArrayList<>(); // 存储已生成的路径段

        // 遍历排好序的障碍物，计算绕行路径并合并
        for (DistanceIndex distanceIndex : distanceIndices) {
            Geometry polygon = polygons.get(distanceIndex.getIndex());
            List<Coordinate> bypassCoordinates = ConflictCheck.check(cuttingLine, polygon);

            // 将当前路径段生成LineString
            LineString currentSegment = geometryFactory.createLineString(bypassCoordinates.toArray(new Coordinate[0]));

            // 检查当前路径段是否与已生成的路径相交
            boolean hasIntersection = false;
            for (LineString existingSegment : pathSegments) {
                if (currentSegment.intersects(existingSegment)) {
                    hasIntersection = true;
                    break;
                }
            }

            // 如果没有交叉点，则添加当前路径段
            if (!hasIntersection) {
                coordinates.addAll(bypassCoordinates);
                pathSegments.add(currentSegment); // 添加到路径段集合中
            }
        }

        coordinates.add(cuttingLine.getCoordinates()[cuttingLine.getCoordinates().length - 1]); // 终点加入路径

        // 生成最终路径，并进行平滑处理
        coordinates = smoothPath(coordinates);

        Geometry finalGeometry = geometryFactory.createLineString(coordinates.toArray(new Coordinate[0]));
        System.out.println(GeoOutUtil.dataDrawLineString(finalGeometry)); // 打印路径

        return coordinates;
    }

    // 判断两个坐标点是否相等，允许一定的容忍误差
    private static boolean areCoordinatesEqual(Coordinate c1, Coordinate c2) {
        final double tolerance = 1E-6; // 精度容忍度，可以根据需求调整
        return Math.abs(c1.x - c2.x) < tolerance && Math.abs(c1.y - c2.y) < tolerance;
    }

    // 平滑路径
    private static List<Coordinate> smoothPath(List<Coordinate> path) {
        List<Coordinate> smoothPath = new ArrayList<>();
        if (path.size() < 2) return path;

        // 对路径进行简单的线性插值或贝塞尔平滑（这里采用简单线性插值示例）
        for (int i = 0; i < path.size() - 1; i++) {
            Coordinate start = path.get(i);
            Coordinate end = path.get(i + 1);
            smoothPath.add(start);
            // 在两点之间加入一个中点来平滑路径
            smoothPath.add(new Coordinate((start.x + end.x) / 2, (start.y + end.y) / 2));
        }
        smoothPath.add(path.get(path.size() - 1)); // 添加最后一个点

        return smoothPath;
    }



    // 解析 Polygon
    private static List<Geometry> parsePolygons(String json) {
        List<Geometry> polygons = new ArrayList<>();
        JSONArray jsonArray = JSON.parseArray(json);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            JSONArray coordsArray = jsonObject.getJSONObject("geometry").getJSONArray("coordinates").getJSONArray(0);
            Coordinate[] coordinates = new Coordinate[coordsArray.size()];
            for (int j = 0; j < coordsArray.size(); j++) {
                JSONArray coordPair = coordsArray.getJSONArray(j);
                coordinates[j] = new Coordinate(coordPair.getDouble(0), coordPair.getDouble(1));
            }
            Polygon polygon = geometryFactory.createPolygon(coordinates);
            polygons.add(GeometryConverter.getBuff(polygon,20));
        }
        return polygons;
    }

    // 解析 LineString
    private static LineString parseLineString(String json) {
        JSONObject jsonObject = JSON.parseObject(json);
        JSONArray coordsArray = jsonObject.getJSONArray("coordinates");
        Coordinate[] coordinates = new Coordinate[coordsArray.size()];
        for (int i = 0; i < coordsArray.size(); i++) {
            JSONArray coordPair = coordsArray.getJSONArray(i);
            coordinates[i] = new Coordinate(coordPair.getDouble(0), coordPair.getDouble(1));
        }
        return geometryFactory.createLineString(coordinates);
    }

    // 切割多边形并获取剩余边界
    private static List<LineString> cutPolygons(List<Polygon> polygons, LineString cuttingLine) {
        List<LineString> remainingEdges = new ArrayList<>();

        for (Polygon polygon : polygons) {
            // 计算 difference (去掉相交部分)
            Geometry result = polygon.difference(cuttingLine);

            // 获取新的边界
            if (result instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) result;
                for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                    Polygon newPolygon = (Polygon) multiPolygon.getGeometryN(i);
                    remainingEdges.add(geometryFactory.createLineString(newPolygon.getExteriorRing().getCoordinates()));
                }
            } else if (result instanceof Polygon) {
                Polygon newPolygon = (Polygon) result;
                remainingEdges.add(geometryFactory.createLineString(newPolygon.getExteriorRing().getCoordinates()));
            }
        }
        return remainingEdges;
    }
}
